#!/usr/python
ident = '$Id: content_search.py 104 2006-05-25 22:06:43Z ahmad $'

# Issue UI
import sys, wx, common, images, re, rex, time, publications
from xml.sax 	import saxutils
from xml.dom	import minidom

# Sort BY and Find By
BY_ALL				= 0
BY_FN				= 1
BY_LN				= 2
BY_ID				= 3
BY_XID				= 4
BY_EMAIL			= 5
BY_COMPANY			= 6
BY_USERNAME			= 7
BY_PASSWORD			= 8
BY_GID				= 9
BY_SPID				= 10
BY_BPID				= 11
ID_CGTIMER_TIMER	= 102


####################################################################################################
# Controls
ID_RPP				= 101
ID_FINDBY_TEXT		= 102
ID_GET_BUTTON		= 103
ID_CONTACTS_LIST	= 104
ID_PAGER			= 105
ID_NEXT_BUTTON  	= 106
ID_PREV_BUTTON  	= 107
ID_SHOWBY			= 108
ID_GROUPS_LIST		= 109
ID_NB				= 110

ID_PUB_OPEN			= 201
ID_ISS_OPEN			= 202

class search_control( wx.Panel ):
	def __init__( self, parent, account, main ):
		wx.Panel.__init__( self, parent, -1 )
		self.parent 	= parent
		self.account 	= account
		self.qualifier	= ""
		self.qid		= ""
		self.format		= 'both'
		self.main		= main
		self.create_menu_items()
		# Connect a timer to this frame
		self.timer = wx.Timer( self, ID_CGTIMER_TIMER )
		self.Bind( wx.EVT_TIMER, self.OnTimer, id=ID_CGTIMER_TIMER )
		# Create the top bar
		self.topbar = wx.BoxSizer( wx.HORIZONTAL )
		# The refresh button
		#self.refresh_button = wx.BitmapButton( self, -1, images.getRefreshBitmap(), size=common.button_size, style=wx.NO_BORDER )
		#self.refresh_button.Bind( wx.EVT_BUTTON, self.OnRefresh )
		#self.topbar.Add( self.refresh_button, 0 )
		# The show selector
		#variables = ['any value', 'header','footer','left','content','right']
		variables = ['any value','left','content','right']
		self.variable_choice = wx.Choice( self, -1, choices=variables )
		self.variable_choice.SetSelection( 0 )
		self.variable_choice.Bind( wx.EVT_CHOICE, self.OnShowByChange )
		self.topbar.Add( self.variable_choice, 1, wx.EXPAND )
		# the relation button
		self.find_rel_button = wx.BitmapButton( self, -1, images.getContainsBitmap(), size=common.button_size, style=wx.NO_BORDER )
		self.find_rel_button.Bind( wx.EVT_BUTTON, self.OnRelChange )
		#self.find_rel_button.Enable( False )
		self.topbar.Add( self.find_rel_button, 0 )
		# The find text box
		self.find_text = wx.TextCtrl( self, -1, '', style=wx.TE_PROCESS_ENTER )
		#self.find_text.Enable( False )
		self.find_text.Bind( wx.EVT_TEXT, self.OnFindTextKeyPress )
		self.find_text.Bind( wx.EVT_TEXT_ENTER, self.OnRefresh )
		self.topbar.Add( self.find_text, 2, wx.EXPAND )
		# the format button
		self.format_button = wx.BitmapButton( self, -1, images.getHtmlTextFormatBitmap(), size=common.button_size, style=wx.NO_BORDER )
		self.format_button.Bind( wx.EVT_BUTTON, self.OnFormatChange )
		self.format_button.Enable( True )
		self.topbar.Add( self.format_button, 0 )
		# The finding selector
		self.rpp_choice = wx.Choice( self, ID_RPP, choices=["10 per page", "30 per page","50 per page", "100 per page"] )
		self.rpp_choice.SetSelection( 1 )
		self.Bind( wx.EVT_CHOICE, self.OnRPPChange, id=ID_RPP )
		self.topbar.Add( self.rpp_choice, 1, wx.EXPAND )
		#self.find_by = 1	# Find by ID by default
		# zoom
		if main:
			self.zoom_button = wx.BitmapButton( self, -1, images.getZoomBitmap(), size=common.button_size, style=wx.NO_BORDER )
			self.zoom_button.Bind( wx.EVT_BUTTON, self.OnZoom )
			self.topbar.Add( self.zoom_button, 0 )
		# Enable the top bar controls
		self.reset_values()
		#self.enable_topbar( True )
		self.filter_set = False
		# Create the list
		self.list = wx.ListCtrl( self, ID_CONTACTS_LIST, style=wx.LC_REPORT )
		self.il = wx.ImageList(16, 16)
		# Load our images
		self.pub_w_icon 	= self.il.Add( images.getFolderWBitmap() )
		self.iss_w_icon 	= self.il.Add( images.getIssueWBitmap() )
		self.pub_n_icon 	= self.il.Add( images.getFolderNBitmap() )
		self.iss_n_icon 	= self.il.Add( images.getIssueNBitmap() )
		self.pub_e_icon 	= self.il.Add( images.getFolderEBitmap() )
		self.iss_e_icon 	= self.il.Add( images.getIssueEBitmap() )
		self.list.SetImageList( self.il, wx.IMAGE_LIST_SMALL )
		# Store the default item color
		self.item_color = self.list.GetTextColour()
		self.list.Bind( wx.EVT_LEFT_DCLICK, self.OnItemDoubleClick )
		# default?
		self.list.Bind( wx.EVT_RIGHT_DOWN, self.OnListRightClick )
		# for wxGTK
		#self.list.Bind( wx.EVT_RIGHT_UP, self.OnListRightClick )
		# for wxMSW
		#self.list.Bind( wx.EVT_COMMAND_RIGHT_CLICK, self.OnListRightClick )
		self.Bind( wx.EVT_LIST_ITEM_SELECTED, self.OnItemActivated, id=ID_CONTACTS_LIST )
		self.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, id=ID_CONTACTS_LIST )
		# Add it's columns
		info = wx.ListItem()
		info.m_mask = wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_format = 0
		info.m_text = "ID"
		self.list.InsertColumnInfo(0, info)

		info.m_text = "Name"
		self.list.InsertColumnInfo(1, info)

		#info.m_text = "Kind"
		#self.list.InsertColumnInfo(2, info)

		# Resize them all
		self.resize_columns()

		# Create the bottom bar
		self.botbar = wx.BoxSizer( wx.HORIZONTAL )

		# Create prev and next buttons
		self.prev_button = wx.BitmapButton( self, -1, images.getLeftArrowBitmap(), style=wx.NO_BORDER )
		self.prev_button.Bind( wx.EVT_BUTTON, self.GetPrev )
		self.prev_button.Enable( False )
		self.botbar.Add( self.prev_button, 0, wx.EXPAND )
		self.pager = wx.StaticText( self, -1, ' ' )
		self.botbar.Add( self.pager, 1, wx.ALIGN_CENTER )
		self.next_button = wx.BitmapButton( self, -1, images.getRightArrowBitmap(), style=wx.NO_BORDER )
		self.next_button.Bind( wx.EVT_BUTTON, self.GetNext )
		self.botbar.Add( self.next_button, 0, wx.EXPAND )
		self.reset_values()
		# The whole mess
		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( self.topbar, 0, wx.EXPAND )
		self.sizer.Add( self.list, 1, wx.EXPAND )
		self.sizer.Add( self.botbar, 0, wx.EXPAND )
		self.SetSizer( self.sizer )
		self.SetAutoLayout( 1 )
		if self.account.window: self.account.window.SetStatusText( "Ready" )
		wx.Yield()
		self.Layout()
		self.Show()

	def OnZoom( self, event ):
		if self.account.window: self.account.window.OnZoom( 2 )

	def OnRelChange( self, event ):
		self.filter_dirty = True
		if self.current_rel == '=':
			self.current_rel = '~'
			self.find_rel_button.SetBitmapLabel( images.getContainsBitmap() )
		elif self.current_rel == '~':
			self.current_rel = '!='
			self.find_rel_button.SetBitmapLabel( images.getNotEqualsBitmap() )
		elif self.current_rel == '!=':
			self.current_rel = '!~'
			self.find_rel_button.SetBitmapLabel( images.getNotContainsBitmap() )
		elif self.current_rel == '!~':
			self.current_rel = '='
			self.find_rel_button.SetBitmapLabel( images.getEqualsBitmap() )
		self.find_text.SetFocus()
		self.update_next_prev_buttons()

	def OnFormatChange( self, event ):
		self.filter_dirty = True
		if self.format == 'both':
			self.format = 'html'
			self.format_button.SetBitmapLabel( images.getHtmlFormatBitmap() )
		elif self.format == 'html':
			self.format = 'text'
			self.format_button.SetBitmapLabel( images.getTextFormatBitmap() )
		elif self.format == 'text':
			self.format = 'both'
			self.format_button.SetBitmapLabel( images.getHtmlTextFormatBitmap() )
		self.find_text.SetFocus()
		self.update_next_prev_buttons()

	def create_menu_items( self ):
		#pubs
		menu = wx.Menu()
		menu.Append( ID_PUB_OPEN, "&Open", " Open" )
		wx.EVT_MENU( self, ID_PUB_OPEN, self.OnPubOpen )
		self.pub_menu = menu
		#isss
		menu = wx.Menu()
		menu.Append( ID_ISS_OPEN, "&Open", " Open" )
		wx.EVT_MENU( self, ID_ISS_OPEN, self.OnIssOpen )
		self.pub_menu = menu
		

	def OnPubOpen( self, event ):
		common.dprint( "OnPubOpen" )
	
	def OnIssOpen( self, event ):
		common.dprint( "OnIssOpen" )
	
	def OnFindTextKeyPress( self, event ):
		self.filter_dirty = True
		self.current_pattern = self.find_text.GetValue()
		self.update_next_prev_buttons()
		common.dprint("current pattern now", self.current_pattern )

	def OnTimer( self, event ):
		self.GetPage()

	def reset_values( self ):
		self.results 			= {}
		self.variable_choice.SetSelection( 0 )
		self.current_variable 	= ''
		self.current_rel		= '~'
		self.current_pattern	= ''
		self.current_max		= 30
		self.current_page		= 0
		self.total_pages		= 0
		self.total_results		= 0
		self.filter_dirty 		= False

	def resize_columns( self ):
		'''Used internally to recalculate the column sizes'''
		# Set the column header sizes
		for i in range( self.list.GetColumnCount() ):
			self.list.SetColumnWidth( i, wx.LIST_AUTOSIZE )

	def OnShowByChange( self, event ):
		variable = self.variable_choice.GetStringSelection()
		variable = variable.strip()
		if variable == self.current_variable: return
		self.filter_dirty = True
		self.current_variable = variable
		#self.find_text.Enable( self.current_variable != '' )
		#self.find_rel_button.Enable( self.current_variable != '' )
		if self.current_variable != '':
			self.find_text.SetFocus()
		self.update_next_prev_buttons()

	def OnRPPChange( self, event ):
		sel = self.rpp_choice.GetSelection()
		if sel == 0 :
			self.current_max = 10
		elif sel == 1 :
			self.current_max = 30
		elif sel == 2 :
			self.current_max = 50
		elif sel == 3 :
			self.current_max = 100
		else:
			self.current_max = 10

	def AppendResult( self, ritem ):
		icon = self.iss_w_icon
		try:
			iss = self.find_issue_by_id( ritem["id"] )
			icon = self.account.window.icon_from_rex_object( iss )
		except:
			pass
		x = self.list.InsertImageStringItem( sys.maxint, ritem['id'], icon )
		self.list.SetStringItem( x , 1, ritem["name"] )
		#self.list.SetStringItem( x , 2, ritem.object_name )
		#self.list.SetItemData( x, x )
		return self.list.GetItem( x )
		
	def OnRefresh( self, event=None ):
		self.GetPage( True )

	def GetPage( self, refresh=False ):
		# Set the filter attibs,
		self.list.DeleteAllItems()
		if self.filter_dirty:
			self.results		= {}
			self.filter_dirty	= False
			self.current_page	= 1
		elif refresh:
			try: del self.results[ self.current_page ]
			except: pass
			if self.current_page == 0: self.current_page = 1

		# Update the status bar
		if self.account.window: self.account.window.SetStatusText( "Getting page %s ..." % self.current_page )
		wx.Yield()
		wx.Yield()
		wx.Yield()
		# Do we use the cache or download ?
		try:
			cache = self.results[ self.current_page ]
		except KeyError:
			cache = None

		if cache:
			for ritem in cache:
				ritem['list_index'] = self.AppendResult( ritem )
		else:
			# Make the call
			cdom = "<search variable=\"%s\" relation=\"%s\" pattern=\"%s\" max=\"%s\" page=\"%s\" format=\"%s\" />" % \
					( self.current_variable, self.current_rel, self.current_pattern, self.current_max, self.current_page, self.format )
			cur = wx.BusyCursor()
			ress = None
			try:
				xmlstring = self.account.execute( 'base', "content_search", DOM=cdom )
				#xmlstring = common.uni2str( xmlstring )
				xmlstring = common.prepare_xml( xmlstring )
				cdom 	= minidom.parseString( xmlstring )
				ress	= cdom.firstChild
			except:
				if self.account.window: self.account.window.SetStatusText( "Ready" )
			del cur
			if not ress: return
			self.total_pages 	= int( ress.attributes["pages"].value )
			self.total_results = int( ress.attributes["count"].value )
			self.results[ self.current_page ] = []
			cache = self.results[ self.current_page ]
			for sr in ress.getElementsByTagName("search_result"):
				search_result = {}
				try:
					search_result['name'] = sr.attributes["name"].value
					search_result['id']	  = sr.attributes["id"].value
					search_result['kind'] = sr.attributes["kind"].value
				except:
					common.show_error( "failed to parse search result [[%s]]" % sr.toxml().encode( 'utf-8' ), False )
				if not search_result: continue
				# Create a list item
				search_result['list_index'] = self.AppendResult( search_result )
				cache.append( search_result )
			#except Exception:
			#	print "Failed to load account contacts."
		self.resize_columns()
		label = "   Page %s of %s [%s total]   " % (self.current_page, self.total_pages, self.total_results)
		#print "Label ", label
		self.pager.SetLabel( label )
		self.update_next_prev_buttons()
		if self.account.window: self.account.window.SetStatusText( "Ready" )
		wx.Yield()

	def GetNext( self, event ):
		# if self.current_page >= self.total_pages: return
		self.timer.Stop()
		self.current_page = self.current_page + 1
		# override?
		if self.filter_dirty:
			self.results		= {}
			self.filter_dirty	= False
			self.current_page	= 1
		if self.account.window: self.account.window.SetStatusText( "Getting page %s ..." % self.current_page )
		#wx.Yield()
		# Cache exists already?
		try:
			cache = self.results[ self.current_page ]
			self.GetPage()
			return
		except KeyError:
			pass
		self.timer.Start( 700, 1 )

	def GetPrev( self, event ):
		if self.current_page <= 1: return
		self.timer.Stop()
		self.current_page = self.current_page - 1
		if self.account.window: self.account.window.SetStatusText( "Getting page %s ..." % self.current_page )
		#wx.Yield()
		# Cache exists already?
		try:
			cache = self.results[ self.current_page ]
			self.GetPage()
			return
		except KeyError:
			pass
		self.timer.Start( 700, 1 )

	def update_next_prev_buttons( self ):
		#print "Checking np %s, %s" % ( self.current_page, self.total_pages )
		if self.filter_dirty:
			self.next_button.Enable( True )
			self.prev_button.Enable( False )
			return
		#
		if self.current_page >= self.total_pages:
			#print "DISABLING next_button"
			self.next_button.Enable( False )
		else:
			#print "ENABLING next_button"
			self.next_button.Enable( True )

		if self.current_page <= 1:
			#print "DISABLING prev_button"
			self.prev_button.Enable( False )
		else:
			#print "ENABLING prev_button"
			self.prev_button.Enable( True )

	def OnListRightClick( self, event ):
		try:
			point = event.GetPositionTuple()
			if wx.Platform == '__WXGTK__':
				point = wx.Point( event.m_x + 5, event.m_y + 45 )
			self.PopupMenu( self.contact_menu, point )
		except:
			pass

	def OnItemDoubleClick( self, event ):
		self.OnEdit( event )

	def OnItemActivated( self, event ):
		self.currentItem = event.m_itemIndex

	def OnEdit( self, event ):
		item = self.results[self.current_page][self.currentItem]
		if item is None: return
		# get the id of the item
		item_id		= item['id']
		item_kind	= item['kind']
		# find an editor for this issue
		pi = common.find_page_index_by_id( self.account.window.ebook, item_id, item_kind )
		# open it up
		if pi > -1:
			try:
				self.account.window.ebook.SetSelection( pi )
				self.account.window.ebook.SetPageImage( pi, self.account.window.icon_from_rex_object( self.account.window.ebook.GetPage().rex_object ) )
				return
			except:
				common.show_error( "Failed to switch to editor", False )
				return
		# we need to find the rex object and open it up for editing
		iss = self.find_issue_by_id( item_id )
		if not iss:
			res = wx.MessageBox( "Could not find in any module, you should reload and try again.", "Not Found" )
			return
		iss.editor = publications.issue( self.account, iss, None )
		# add the page
		self.account.window.ebook.AddPage( iss.editor, iss.editor.get_label_text() )
		pi = common.get_page_index( self.account.window.ebook, iss.editor )
		try:
			self.account.window.ebook.SetSelection( pi )
			self.account.window.ebook.SetPageImage( pi, self.account.window.icon_from_rex_object( iss ) )
		except:
			common.show_error("Failed to switch to editor", False)

	def get_cache( self ):
		try:
			cache = self.results[ self.current_page ]
		except KeyError:
			self.results[ self.current_page ] = []
			cache = self.results[ self.current_page ]
		return cache

	def get_selected( self ):
		sel = []
		count = self.list.GetItemCount()
		if count < 1: return sel
		for i in range( 0, count ):
			if self.list.IsSelected( i ):
				sel.append( self.results[ self.current_page ][i] )
		return sel
	
	def find_issue_by_id( self, id ):
		rex_object = None
		# find it in the web control
		if not rex_object:
			for pub in self.account.window.web_control.publications:
				for iss in pub.issues:
					if iss['id'] == id:
						rex_object = iss
						break
		# find it in the web control
		if not rex_object:
			for pub in self.account.window.newsletter_control.publications:
				for iss in pub.issues:
					if iss['id'] == id:
						rex_object = iss
						break
		# find it in the web control
		if not rex_object:
			for pub in self.account.window.email_control.publications:
				for iss in pub.issues:
					if iss['id'] == id:
						rex_object = iss
						break
		return rex_object
